﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CoreUtils.Common
{
    public class Drawing
    {
        /// <summary>
        /// Draw a circle on overlay given it's object data
        /// </summary>
        /// <param name="pOverlay">ref overlay</param>
        /// <param name="circle">circle need to be drawn</param>
        /// <remarks>trungpv@vnext.vn</remarks>
        public static void drawCircle(ref FVIL.GDI.CFviOverlay pOverlay, FVIL.Data.CFviCircle circle,
            double angle, System.Drawing.Color radiusColor, FVIL.GDI.CFviGdiPen penStyle)
        {
            // Draw circle to overlay
            FVIL.GDI.CFviGdiCircle dCircle = new FVIL.GDI.CFviGdiCircle(circle);
            dCircle.Pen = penStyle;
            pOverlay.Figures.Add(dCircle);

            // Draw center to overlay
            FVIL.GDI.CFviGdiPoint dCenter = new FVIL.GDI.CFviGdiPoint(circle.Center);
            dCenter.Pen.Width = 2;
            dCenter.Size = new System.Drawing.Size(8, 8);
            dCenter.Pen.Color = penStyle.Color;
            dCenter.Style = FVIL.GDI.FigureStyle.Cross;
            pOverlay.Figures.Add(dCenter);

            // Draw radius to overlay
            drawDistance(ref pOverlay, circle.Center,
                new FVIL.Data.CFviPoint(circle.Center.X + circle.Radius * Math.Cos(angle),
                    circle.Center.Y - circle.Radius * Math.Sin(angle)), "", radiusColor, radiusColor);
        }

        /// <summary>
        /// Draw a circle on overlay given it's center and radius
        /// </summary>
        /// <param name="pOverlay">ref overlay</param>
        /// <param name="circle">circle need to be drawn</param>
        /// <remarks>trungpv@vnext.vn</remarks>
        public static void drawCircle(ref FVIL.GDI.CFviOverlay pOverlay,
            FVIL.Data.CFviPoint center, double radius, double angle,
            System.Drawing.Color radiusColor, FVIL.GDI.CFviGdiPen penStyle)
        {
            drawCircle(ref pOverlay, new FVIL.Data.CFviCircle(center, radius), angle,
                radiusColor, penStyle);
        }

        /// <summary>
        /// Draw a arrow (2 direction) given start and end point
        /// </summary>
        /// <param name="pOverlay">ref overlay</param>
        /// <param name="stPoint">Start point</param>
        /// <param name="edPoint">End point</param>
        /// <remarks>trungpv@vnext.vn</remarks>
        public static void drawDistance(ref FVIL.GDI.CFviOverlay pOverlay, FVIL.Data.CFviPoint stPoint,
            FVIL.Data.CFviPoint edPoint, string note, System.Drawing.Color lineColor, System.Drawing.Color noteColor)
        {
            // Draw starting and ending point with arrow 
            FVIL.Data.CFviPoint[] lsPoint = new FVIL.Data.CFviPoint[2] { stPoint, edPoint };
            for (int i = 0; i < 2; i++)
            {
                FVIL.GDI.CFviGdiAnchor anchor = new FVIL.GDI.CFviGdiAnchor(lsPoint[i], lsPoint[1 - i]);
                anchor.Pen.Color = lineColor;
                anchor.Pen.Width = 2;
                anchor.Style = FVIL.GDI.FigureStyle.Arrow;
                anchor.Position = lsPoint[i];
                pOverlay.Figures.Add(anchor);
            }

            // Draw line connecting 2 points
            FVIL.Data.CFviLineSegment lineseg = new FVIL.Data.CFviLineSegment(lsPoint[0], lsPoint[1]);
            FVIL.GDI.CFviGdiLineSegment line = new FVIL.GDI.CFviGdiLineSegment(lineseg);
            line.Pen.Color = lineColor;
            line.Pen.Width = 2;
            pOverlay.Figures.Add(line);

            // Draw distance value above 
            FVIL.GDI.CFviGdiString distance = new FVIL.GDI.CFviGdiString();
            distance.Text = (Math.Sqrt(Math.Pow(line.Width, 2) +
                Math.Pow(line.Height, 2))).ToString("0") + " px" + note;
            distance.Font.Weight = FVIL.GDI.FontWeight.Bold;
            distance.Font.Width = 6;
            distance.Font.Height = 12;
            distance.Align = FVIL.GDI.TextAlign.Left | FVIL.GDI.TextAlign.Top;
            distance.BkMode = FVIL.GDI.BkMode.Transparent;
            distance.Color = noteColor;

            // Compute line angle
            FVIL.Data.CFviAngle _angle = new FVIL.Data.CFviAngle();
            _angle = FVIL.Caliper.Function.Angle(stPoint, edPoint);
            distance.Angle = _angle;
            distance.Position = (stPoint + edPoint) / 2;
            distance.VAlign = FVIL.GDI.VTextAlign.Left;
            pOverlay.Figures.Add(distance);
        }

        /// <summary>
        /// Draw a rectangle with size and coordinate
        /// </summary>
        /// <param name="rect">rectangle</param>
        /// <remarks>trungpv@vnext.vn</remarks>
        public static void drawRectangle(ref FVIL.GDI.CFviOverlay pOverlay, FVIL.Data.CFviRectangle rect, double positionOffset)
        {
            // Draw rectangle
            FVIL.GDI.CFviGdiRectangle dRect = new FVIL.GDI.CFviGdiRectangle(rect);
            dRect.Pen.Color = System.Drawing.Color.FromArgb(0xFF, 0x00, 0x00);
            dRect.Pen.Width = 2;
            pOverlay.Figures.Add(dRect);

            // Compute 4 peaks of rectangle
            FVIL.Data.CFviPoint topLeftPoint = rect.St;
            FVIL.Data.CFviPoint bottomLeftPoint = new FVIL.Data.CFviPoint(rect.Left, rect.Bottom);
            FVIL.Data.CFviPoint bottomRightPoint = rect.Ed;
            FVIL.Data.CFviPoint topRightPoint = new FVIL.Data.CFviPoint(rect.Right, rect.Top);
            FVIL.Data.CFviPoint[] lsPoint = new FVIL.Data.CFviPoint[6] { topRightPoint, 
                topLeftPoint, bottomLeftPoint, bottomRightPoint, topRightPoint, topLeftPoint};
            // Compute position of top peak
            double angle = (rect.Angle.Degree >= 0) && (rect.Angle.Degree < 360) ? rect.Angle.Degree : 360 + rect.Angle.Degree;
            int quadrantNb = (angle == 0) ? 3 : (int)angle / 90;
            // Compute offset distance to draw width and height 
            int offsetX = ((quadrantNb - 1) % 2) * 10;
            int offsetY = ((2 - quadrantNb) % 2) * 10;

            // Compute 4 points to draw distance
            FVIL.Data.CFviPoint dTopPoint1 = FVIL.Math.Rotate(new FVIL.Data.CFviPoint(
                lsPoint[quadrantNb + 1].X + offsetX, lsPoint[quadrantNb + 1].Y + offsetY),
                rect.Center + rect.St, new FVIL.Data.CFviAngle(angle));
            FVIL.Data.CFviPoint dLeftPoint = FVIL.Math.Rotate(new FVIL.Data.CFviPoint(
                lsPoint[quadrantNb + 2].X + offsetX, lsPoint[quadrantNb + 2].Y + offsetY),
                rect.Center + rect.St, new FVIL.Data.CFviAngle(angle));
            FVIL.Data.CFviPoint dTopPoint2 = FVIL.Math.Rotate(new FVIL.Data.CFviPoint(
                lsPoint[quadrantNb + 1].X - offsetY, lsPoint[quadrantNb + 1].Y + offsetX),
                rect.Center + rect.St, new FVIL.Data.CFviAngle(angle));
            FVIL.Data.CFviPoint dRightPoint = FVIL.Math.Rotate(new FVIL.Data.CFviPoint(
                lsPoint[quadrantNb].X - offsetY, lsPoint[quadrantNb].Y + offsetX),
                rect.Center + rect.St, new FVIL.Data.CFviAngle(angle));
            FVIL.Data.CFviPoint gTopPoint = lsPoint[quadrantNb + 1];
            drawDistance(ref pOverlay, dLeftPoint, dTopPoint1, "",
                System.Drawing.Color.Red, System.Drawing.Color.Red);
            drawDistance(ref pOverlay, dTopPoint2, dRightPoint, "",
                System.Drawing.Color.Red, System.Drawing.Color.Red);

            // Draw top left position of rectangle
            FVIL.GDI.CFviGdiString coordinate = new FVIL.GDI.CFviGdiString();
            coordinate.Font.Height = 12;
            coordinate.Font.Width = 6;
            coordinate.Position = FVIL.Math.Rotate(gTopPoint, rect.Center + rect.St, new FVIL.Data.CFviAngle(angle)) - positionOffset;
            coordinate.Text = "(" + coordinate.Position.X.ToString("0") + "," + coordinate.Position.Y.ToString("0") + ")";
            coordinate.Color = System.Drawing.Color.Red;
            coordinate.VAlign = FVIL.GDI.VTextAlign.Left;
            pOverlay.Figures.Add(coordinate);
        }

        /// <summary>
        /// Draw a note with position, size, angle, color
        /// </summary>
        /// <param name="pOverlay">ref overlay</param>
        /// <param name="text">text</param>
        /// <param name="angle">angle</param>
        /// <param name="size">siz</param>
        /// <param name="color">color</param>
        /// <param name="position">position</param>
        /// <remarks>trungpv@vnext.vn</remarks>
        public static void drawNotes(ref FVIL.GDI.CFviOverlay pOverlay, string text, double angle,
            System.Drawing.Size size, System.Drawing.Color color, FVIL.Data.CFviPoint position)
        {
            // Draw orientation and text
            FVIL.GDI.CFviGdiString dText = new FVIL.GDI.CFviGdiString(text);
            dText.Font.Size = size;
            dText.Color = color;
            // Add angle of orientation text
            dText.Angle = new FVIL.Data.CFviAngle(angle);
            dText.Position = position;
            pOverlay.Figures.Add(dText);
        }

        /// <summary>
        /// Draw a cell grid with cell's size and grid's position
        /// </summary>
        /// <param name="pOverlay">overlay</param>
        /// <param name="nbX">number of cell (axis X)</param>
        /// <param name="nbY">number of cell (axis Y)</param>
        /// <param name="sizeX">size of X cell</param>
        /// <param name="sizeY">size of Y cell</param>
        /// <param name="posX">position X of grid</param>
        /// <param name="posY">position Y of gỉd</param>
        /// <remarks>trungpv@vnext.vn</remarks>
        public static void drawCellGrid(ref FVIL.GDI.CFviOverlay pOverlay, int nbX, int nbY,
            int sizeX, int sizeY, int posX, int posY)
        {
            // Draw vertical lines
            for (int i = 0; i < nbX + 1; i++)
            {
                FVIL.Data.CFviLineSegment linesegVert = new FVIL.Data.CFviLineSegment(
                    new FVIL.Data.CFviPoint(posX + i * sizeX, posY),
                    new FVIL.Data.CFviPoint(posX + i * sizeX, posY + nbY * sizeY));
                FVIL.GDI.CFviGdiLineSegment line = new FVIL.GDI.CFviGdiLineSegment(linesegVert);
                line.Pen.Color = System.Drawing.Color.Orange;
                line.Pen.Width = 2;
                pOverlay.Figures.Add(line);
            }
            // Draw horizontal lines
            for (int i = 0; i < nbY + 1; i++)
            {
                FVIL.Data.CFviLineSegment linesegHorz = new FVIL.Data.CFviLineSegment(
                    new FVIL.Data.CFviPoint(posX, posY + i * sizeY),
                    new FVIL.Data.CFviPoint(posX + nbX * sizeX, posY + i * sizeY));
                FVIL.GDI.CFviGdiLineSegment line = new FVIL.GDI.CFviGdiLineSegment(linesegHorz);
                line.Pen.Color = System.Drawing.Color.Orange;
                line.Pen.Width = 2;
                pOverlay.Figures.Add(line);
            }
        }

        /// <summary>
        /// Draw score of a pattern with bouding rectangle
        /// </summary>
        /// <param name="pOverlay">ref overlay</param>
        /// <param name="pattern">pattern to draw</param>
        /// <param name="data"></param>
        /// <remarks>trungpv@vnext.vn</remarks>
        public static void drawPatternScore(ref FVIL.GDI.CFviOverlay pOverlay, FVIL.Data.CFviPattern pattern,
           fvalgcli.F_GS_RESULT data, double offsetX, double offsetY, System.Drawing.Color patternColor,
            System.Drawing.Color scoreColor)
        {
            FVIL.Data.CFviPoint mark = new FVIL.Data.CFviPoint(offsetX + data.x / 100, offsetY + data.y / 100);
            FVIL.Data.CFviPoint pat_mark = pattern.CenterMark;
            FVIL.Data.CFviRectangle pat_rect = pattern.RegistRect;

            FVIL.Data.CFviRectangle rect = new FVIL.Data.CFviRectangle();
            rect.St = new FVIL.Data.CFviPoint(mark.X - pat_mark.X, mark.Y - pat_mark.Y);
            rect.Ed = new FVIL.Data.CFviPoint(rect.X + pat_rect.Width, rect.Y + pat_rect.Height);

            System.String score = data.score.ToString("0.#") + "%";

            FVIL.GDI.CFviGdiImage _fill = new FVIL.GDI.CFviGdiImage();
            _fill.SetSize(1, 1, 32);
            _fill.Position = rect.St;
            _fill.Alpha = 0x3F;
            _fill.StretchHorzSize = (int)(rect.Width);
            _fill.StretchVertSize = (int)(rect.Height);
            _fill.SetPixelRGB(0, 0, patternColor);

            FVIL.GDI.CFviGdiRectangle _rect = new FVIL.GDI.CFviGdiRectangle(rect);
            _rect.Pen.Color = patternColor;

            FVIL.GDI.CFviGdiPoint _mark = new FVIL.GDI.CFviGdiPoint(mark);
            _mark.Size = new System.Drawing.Size(5, 5);
            _mark.Pen.Color = System.Drawing.Color.Blue;

            FVIL.GDI.CFviGdiString _score = new FVIL.GDI.CFviGdiString();
            _score.Font.Width = (int)(rect.Width / 30);
            _score.Font.Height = (int)(rect.Height / 15);
            _score.Text = "スコア： " + score.ToString();
            _score.Position = mark;
            _score.Align = FVIL.GDI.TextAlign.Left | FVIL.GDI.TextAlign.Top;
            _score.BkMode = FVIL.GDI.BkMode.Transparent;
            _score.Color = scoreColor;

            pOverlay.Figures.Add(_fill);
            pOverlay.Figures.Add(_rect);
            pOverlay.Figures.Add(_mark);
            pOverlay.Figures.Add(_score);
        }
    }
}
